#include "stretchanimation.h"

StretchAnimation::StretchAnimation(QWidget *parent) : parent(parent)
  ,valid(false)
  ,gap(0)
  ,duration(100)
  ,direction(LEFT)
  ,isRunning(false)
  ,borderSpace(0)
  ,statPos(0)
  ,widget(nullptr)
{
    Widget * w = qobject_cast<Widget*>(parent);
    if (w){
        this->widget = w;
        this->parent = w->getCentreWidget();
        connect(widget,SIGNAL(sizeChanged(QSize)),this,SLOT(showNormal()));
    }
    if (this->parent){
        valid = true;
    }
    size = QSize(60,60);
    styleSheet = "QPushButton{background-color:#363840;color:white;}QPushButton:press{background-color:#000409;border-width:3px;border-color:rgb(237,237,237)}QPushButton:hover{background-color:#000409}";
}

QList<QPushButton *> StretchAnimation::getButtonList() const
{
    return buttonList;
}

void StretchAnimation::setButtonList(const QList<QPushButton *> &value)
{
    for (QPushButton* b : buttonList){
        disconnect(b,SIGNAL(clicked(bool)),this,SLOT(buttonClicked()));
    }
    buttonList.clear();
    buttonList = value;
    for (QPushButton * btn : value){
        btn->setParent(this->parent);
        btn->resize(size);
        connect(btn,SIGNAL(clicked(bool)),this,SLOT(buttonClicked()));
        btn->setStyleSheet(styleSheet);
    }
    resetFramePos();
    startAnimation();
}

QWidget *StretchAnimation::getParent() const
{
    return parent;
}

bool StretchAnimation::getValid() const
{
    return valid;
}

int StretchAnimation::getGap() const
{
    return gap;
}

void StretchAnimation::setGap(int value)
{
    gap = value;
    showNormal();
}

int StretchAnimation::getDuration() const
{
    return duration;
}

void StretchAnimation::setDuration(int value)
{
    duration = value;
    startAnimation();
}

void StretchAnimation::resetFramePos()
{
    pointList.clear();
    if (!valid){
        return;
    }
    int y=statPos;
    for (QPushButton * btn : buttonList){
        switch(direction){
        case LEFT:
            pointList.append(QPoint(borderSpace,y));
            y+=btn->height()-3+gap;
            break;
        case RIGHT:
            pointList.append(QPoint(parent->width()-btn->width()-borderSpace,y));
            y+=btn->height()-3+gap;
            break;
        case UP:
            pointList.append(QPoint(y,borderSpace));
            y+=btn->width()-3+gap;
            break;
        case DOWN:
            pointList.append(QPoint(y,parent->height()-btn->height()-borderSpace));
            y+=btn->width()-3+gap;
            break;
        }
    }
}

void StretchAnimation::loops(QPropertyAnimation *animation)
{
    QEventLoop loop;
    connect(animation, SIGNAL(finished()), &loop, SLOT(quit()));
    animation->start();
    loop.exec();
}

void StretchAnimation::setStyleSheet(const QString &value)
{
    styleSheet = value;
    for (QPushButton * b : buttonList){
        b->setStyleSheet(styleSheet);
    }
}

void StretchAnimation::showNormal()
{
    resetFramePos();
    if (isStretch){
        for (int i=0; i<buttonList.count(); ++i){
            buttonList.at(i)->move(pointList.at(i));
        }
    }
}

void StretchAnimation::test()
{
    if (isStretch){
        closeAnimation(buttonList.at(3));
    }else{
        startAnimation();
    }
}

void StretchAnimation::buttonClicked()
{
    QObject* object = sender();
    QPushButton * button = qobject_cast<QPushButton*>(object);
    if (button){
        closeAnimation(button);
    }
}

int StretchAnimation::getStatPos() const
{
    return statPos;
}

void StretchAnimation::setStartPos(int value)
{
    statPos = value;
    showNormal();
}

QEasingCurve StretchAnimation::getOffCurve() const
{
    return offCurve;
}

void StretchAnimation::setOffCurve(const QEasingCurve &value)
{
    offCurve = value;
}

QEasingCurve StretchAnimation::getStretchCurve() const
{
    return stretchCurve;
}

void StretchAnimation::setStretchCurve(const QEasingCurve &value)
{
    stretchCurve = value;
}

int StretchAnimation::getBorderSpace() const
{
    return borderSpace;
}

void StretchAnimation::setBorderSpace(int value)
{
    borderSpace = value;
    showNormal();
}

QSize StretchAnimation::getSize() const
{
    return size;
}

void StretchAnimation::setSize(const QSize &value)
{
    size = value;
    showNormal();
}

StretchAnimation::DIRECTION StretchAnimation::getDirection() const
{
    return direction;
}

void StretchAnimation::setDirection(const StretchAnimation::DIRECTION &value)
{
    direction = value;
    showNormal();
}

void StretchAnimation::startAnimation()
{
    if ((!valid) || isRunning || isStretch){
        return;
    }
    isRunning = true;
    isStretch = true;
    for (int i = 0; i< buttonList.count(); ++i){
        QPropertyAnimation animation(buttonList.at(i),"geometry");
        animation.setEasingCurve(stretchCurve);
        animation.setDuration(duration);
        if (0==i){
            switch (direction) {
            case LEFT:
                animation.setStartValue(QRect(pointList.at(i),QSize(0,size.height())));
                break;
            case RIGHT:
                animation.setStartValue(QRect((pointList.at(i)+QPoint(size.width(),0)),QSize(0,size.height())));
                break;
            case UP:
                animation.setStartValue(QRect(pointList.at(i),QSize(size.width(),0)));
                break;
            case DOWN:
                animation.setStartValue(QRect(pointList.at(i)-QPoint(size.height(),0),QSize(0,size.height())));
                break;
            default:
                break;
            }
        }else{
            switch (direction) {
            case LEFT:
            case RIGHT:
                animation.setStartValue(QRect(pointList.at(i),QSize(size.width(),0)));
                break;
            case UP:
            case DOWN:
                animation.setStartValue(QRect(pointList.at(i),QSize(0,size.height())));
                break;
            default:
                break;
            }
        }
        animation.setEndValue(QRect(pointList.at(i),size));
        buttonList.at(i)->setVisible(true);
        loops(&animation);
    }
    isRunning = false;
}

void StretchAnimation::closeAnimation(QPushButton *btn)
{
    if (isRunning && (!isStretch) && valid){
        return;
    }
    isRunning = true;
    isStretch = false;
    int border = -1;
    QList<QPushButton*> startList;
    QList<QPoint> startPoint;
    for (int i=0; i<buttonList.count(); ++i){
        if (btn == buttonList.at(i)){
            border = i;
            break;
        }
        startList.append(buttonList.at(i));
        startPoint.append(pointList.at(i));
    }
    QList<QPushButton*> endList;
    QList<QPoint> endPoint;
    if (border == -1){
        return;
    }
    for (int t=buttonList.count()-1; t>border; --t){
        endList.append(buttonList.at(t));
        endPoint.append(pointList.at(t));
    }
    int maxCount = startList.count()>endList.count()?startList.count():endList.count();
    for (int i=0; i<maxCount;++i){
        bool a = false;
        bool b = false;
        QPropertyAnimation animationA;
        QPropertyAnimation animationB;
        if (i<startList.count()){
            animationA.setTargetObject(startList.at(i));
            animationA.setPropertyName("geometry");
            animationA.setDuration(duration);
            animationA.setEasingCurve(offCurve);
            switch (direction) {
            case LEFT:
            case RIGHT:
                animationA.setEndValue(QRect(startPoint.at(i)+QPoint(0,size.height()),QSize(size.width(),0)));
                break;
            case UP:
            case DOWN:
                animationA.setEndValue(QRect(startList.at(i)->pos()+QPoint(size.width(),0),QSize(0,size.height())));
                break;
            default:
                break;
            }
            animationA.setStartValue(QRect(startPoint.at(i),size));
            a = true;
        }
        if (i<endList.count()){
            animationB.setTargetObject(endList.at(i));
            animationB.setPropertyName("geometry");
            animationB.setDuration(duration);
            animationB.setEasingCurve(offCurve);
            switch (direction) {
            case LEFT:
            case RIGHT:
                animationB.setEndValue(QRect(endList.at(i)->pos(),QSize(size.width(),0)));
                break;
            case UP:
            case DOWN:
                animationB.setEndValue(QRect(endList.at(i)->pos(),QSize(0,size.height())));
                break;
            default:
                break;
            }
            animationB.setStartValue(QRect(endPoint.at(i),size));
            b = true;
            }
        if (a&&b){
            animationA.start();
            loops(&animationB);
            startList.at(i)->setVisible(false);
            endList.at(i)->setVisible(false);
        }else if(a){
            loops(&animationA);
            startList.at(i)->setVisible(false);
        }else{
            loops(&animationB);
            endList.at(i)->setVisible(false);
        }
    }
    QPropertyAnimation animationBorder(buttonList.at(border),"geometry");
    animationBorder.setDuration(duration);
    animationBorder.setEasingCurve(offCurve);
    animationBorder.setStartValue(QRect(pointList.at(border),size));
    switch (direction) {
    case LEFT:
        animationBorder.setEndValue(QRect(pointList.at(border),QSize(0,size.height())));
        break;
    case RIGHT:
        animationBorder.setEndValue(QRect(pointList.at(border)+QPoint(size.width(),0),QSize(0,size.height())));
        break;
    case UP:
        animationBorder.setEndValue(QRect(pointList.at(border),QSize(size.width(),0)));
        break;
    case DOWN:
        animationBorder.setEndValue(QRect(pointList.at(border)+QPoint(0,size.height()),QSize(size.width(),0)));
        break;
    default:
        break;
    }
    loops(&animationBorder);
    buttonList.at(border)->setVisible(false);
    isRunning = false;
}
